/*-------------------------------------------------------------------------
 *
 * network_gist.c
 *      GiST support for network types.
 *
 * The key thing to understand about this code is the definition of the
 * "union" of a set of INET/CIDR values.  It works like this:
 * 1. If the values are not all of the same IP address family, the "union"
 * is a dummy value with family number zero, minbits zero, commonbits zero,
 * address all zeroes.  Otherwise:
 * 2. The union has the common IP address family number.
 * 3. The union's minbits value is the smallest netmask length ("ip_bits")
 * of all the input values.
 * 4. Let C be the number of leading address bits that are in common among
 * all the input values (C ranges from 0 to ip_maxbits for the family).
 * 5. The union's commonbits value is C.
 * 6. The union's address value is the same as the common prefix for its
 * first C bits, and is zeroes to the right of that.  The physical width
 * of the address value is ip_maxbits for the address family.
 *
 * In a leaf index entry (representing a single key), commonbits is equal to
 * ip_maxbits for the address family, minbits is the same as the represented
 * value's ip_bits, and the address is equal to the represented address.
 * Although it may appear that we're wasting a byte by storing the union
 * format and not just the represented INET/CIDR value in leaf keys, the
 * extra byte is actually "free" because of alignment considerations.
 *
 * Note that this design tracks minbits and commonbits independently; in any
 * given union value, either might be smaller than the other.  This does not
 * help us much when descending the tree, because of the way inet comparison
 * is defined: at non-leaf nodes we can't compare more than minbits bits
 * even if we know them.  However, it greatly improves the quality of split
 * decisions.  Preliminary testing suggests that searches are as much as
 * twice as fast as for a simpler design in which a single field doubles as
 * the common prefix length and the minimum ip_bits value.
 *
 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *      src/backend/utils/adt/network_gist.c
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include <sys/socket.h>

#include "access/gist.h"
#include "access/stratnum.h"
#include "utils/builtins.h"
#include "utils/inet.h"

/*
 * Operator strategy numbers used in the GiST inet_ops opclass
 */
#define INETSTRAT_OVERLAPS        RTOverlapStrategyNumber
#define INETSTRAT_EQ            RTEqualStrategyNumber
#define INETSTRAT_NE            RTNotEqualStrategyNumber
#define INETSTRAT_LT            RTLessStrategyNumber
#define INETSTRAT_LE            RTLessEqualStrategyNumber
#define INETSTRAT_GT            RTGreaterStrategyNumber
#define INETSTRAT_GE            RTGreaterEqualStrategyNumber
#define INETSTRAT_SUB            RTSubStrategyNumber
#define INETSTRAT_SUBEQ            RTSubEqualStrategyNumber
#define INETSTRAT_SUP            RTSuperStrategyNumber
#define INETSTRAT_SUPEQ            RTSuperEqualStrategyNumber


/*
 * Representation of a GiST INET/CIDR index key.  This is not identical to
 * INET/CIDR because we need to keep track of the length of the common address
 * prefix as well as the minimum netmask length.  However, as long as it
 * follows varlena header rules, the core GiST code won't know the difference.
 * For simplicity we always use 1-byte-header varlena format.
 */
typedef struct GistInetKey
{
    uint8        va_header;        /* varlena header --- don't touch directly */
    unsigned char family;        /* PGSQL_AF_INET, PGSQL_AF_INET6, or zero */
    unsigned char minbits;        /* minimum number of bits in netmask */
    unsigned char commonbits;    /* number of common prefix bits in addresses */
    unsigned char ipaddr[16];    /* up to 128 bits of common address */
} GistInetKey;

#define DatumGetInetKeyP(X) ((GistInetKey *) DatumGetPointer(X))
#define InetKeyPGetDatum(X) PointerGetDatum(X)

/*
 * Access macros; not really exciting, but we use these for notational
 * consistency with access to INET/CIDR values.  Note that family-zero values
 * are stored with 4 bytes of address, not 16.
 */
#define gk_ip_family(gkptr)        ((gkptr)->family)
#define gk_ip_minbits(gkptr)    ((gkptr)->minbits)
#define gk_ip_commonbits(gkptr) ((gkptr)->commonbits)
#define gk_ip_addr(gkptr)        ((gkptr)->ipaddr)
#define ip_family_maxbits(fam)    ((fam) == PGSQL_AF_INET6 ? 128 : 32)

/* These require that the family field has been set: */
#define gk_ip_addrsize(gkptr) \
    (gk_ip_family(gkptr) == PGSQL_AF_INET6 ? 16 : 4)
#define gk_ip_maxbits(gkptr) \
    ip_family_maxbits(gk_ip_family(gkptr))
#define SET_GK_VARSIZE(dst) \
    SET_VARSIZE_SHORT(dst, offsetof(GistInetKey, ipaddr) + gk_ip_addrsize(dst))


/*
 * The GiST query consistency check
 */
Datum
inet_gist_consistent(PG_FUNCTION_ARGS)
{// #lizard forgives
    GISTENTRY  *ent = (GISTENTRY *) PG_GETARG_POINTER(0);
    inet       *query = PG_GETARG_INET_PP(1);
    StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);

    /* Oid        subtype = PG_GETARG_OID(3); */
    bool       *recheck = (bool *) PG_GETARG_POINTER(4);
    GistInetKey *key = DatumGetInetKeyP(ent->key);
    int            minbits,
                order;

    /* All operators served by this function are exact. */
    *recheck = false;

    /*
     * Check 0: different families
     *
     * If key represents multiple address families, its children could match
     * anything.  This can only happen on an inner index page.
     */
    if (gk_ip_family(key) == 0)
    {
        Assert(!GIST_LEAF(ent));
        PG_RETURN_BOOL(true);
    }

    /*
     * Check 1: different families
     *
     * Matching families do not help any of the strategies.
     */
    if (gk_ip_family(key) != ip_family(query))
    {
        switch (strategy)
        {
            case INETSTRAT_LT:
            case INETSTRAT_LE:
                if (gk_ip_family(key) < ip_family(query))
                    PG_RETURN_BOOL(true);
                break;

            case INETSTRAT_GE:
            case INETSTRAT_GT:
                if (gk_ip_family(key) > ip_family(query))
                    PG_RETURN_BOOL(true);
                break;

            case INETSTRAT_NE:
                PG_RETURN_BOOL(true);
        }
        /* For all other cases, we can be sure there is no match */
        PG_RETURN_BOOL(false);
    }

    /*
     * Check 2: network bit count
     *
     * Network bit count (ip_bits) helps to check leaves for sub network and
     * sup network operators.  At non-leaf nodes, we know every child value
     * has ip_bits >= gk_ip_minbits(key), so we can avoid descending in some
     * cases too.
     */
    switch (strategy)
    {
        case INETSTRAT_SUB:
            if (GIST_LEAF(ent) && gk_ip_minbits(key) <= ip_bits(query))
                PG_RETURN_BOOL(false);
            break;

        case INETSTRAT_SUBEQ:
            if (GIST_LEAF(ent) && gk_ip_minbits(key) < ip_bits(query))
                PG_RETURN_BOOL(false);
            break;

        case INETSTRAT_SUPEQ:
        case INETSTRAT_EQ:
            if (gk_ip_minbits(key) > ip_bits(query))
                PG_RETURN_BOOL(false);
            break;

        case INETSTRAT_SUP:
            if (gk_ip_minbits(key) >= ip_bits(query))
                PG_RETURN_BOOL(false);
            break;
    }

    /*
     * Check 3: common network bits
     *
     * Compare available common prefix bits to the query, but not beyond
     * either the query's netmask or the minimum netmask among the represented
     * values.  If these bits don't match the query, we have our answer (and
     * may or may not need to descend, depending on the operator).  If they do
     * match, and we are not at a leaf, we descend in all cases.
     *
     * Note this is the final check for operators that only consider the
     * network part of the address.
     */
    minbits = Min(gk_ip_commonbits(key), gk_ip_minbits(key));
    minbits = Min(minbits, ip_bits(query));

    order = bitncmp(gk_ip_addr(key), ip_addr(query), minbits);

    switch (strategy)
    {
        case INETSTRAT_SUB:
        case INETSTRAT_SUBEQ:
        case INETSTRAT_OVERLAPS:
        case INETSTRAT_SUPEQ:
        case INETSTRAT_SUP:
            PG_RETURN_BOOL(order == 0);

        case INETSTRAT_LT:
        case INETSTRAT_LE:
            if (order > 0)
                PG_RETURN_BOOL(false);
            if (order < 0 || !GIST_LEAF(ent))
                PG_RETURN_BOOL(true);
            break;

        case INETSTRAT_EQ:
            if (order != 0)
                PG_RETURN_BOOL(false);
            if (!GIST_LEAF(ent))
                PG_RETURN_BOOL(true);
            break;

        case INETSTRAT_GE:
        case INETSTRAT_GT:
            if (order < 0)
                PG_RETURN_BOOL(false);
            if (order > 0 || !GIST_LEAF(ent))
                PG_RETURN_BOOL(true);
            break;

        case INETSTRAT_NE:
            if (order != 0 || !GIST_LEAF(ent))
                PG_RETURN_BOOL(true);
            break;
    }

    /*
     * Remaining checks are only for leaves and basic comparison strategies.
     * See network_cmp_internal() in network.c for the implementation we need
     * to match.  Note that in a leaf key, commonbits should equal the address
     * length, so we compared the whole network parts above.
     */
    Assert(GIST_LEAF(ent));

    /*
     * Check 4: network bit count
     *
     * Next step is to compare netmask widths.
     */
    switch (strategy)
    {
        case INETSTRAT_LT:
        case INETSTRAT_LE:
            if (gk_ip_minbits(key) < ip_bits(query))
                PG_RETURN_BOOL(true);
            if (gk_ip_minbits(key) > ip_bits(query))
                PG_RETURN_BOOL(false);
            break;

        case INETSTRAT_EQ:
            if (gk_ip_minbits(key) != ip_bits(query))
                PG_RETURN_BOOL(false);
            break;

        case INETSTRAT_GE:
        case INETSTRAT_GT:
            if (gk_ip_minbits(key) > ip_bits(query))
                PG_RETURN_BOOL(true);
            if (gk_ip_minbits(key) < ip_bits(query))
                PG_RETURN_BOOL(false);
            break;

        case INETSTRAT_NE:
            if (gk_ip_minbits(key) != ip_bits(query))
                PG_RETURN_BOOL(true);
            break;
    }

    /*
     * Check 5: whole address
     *
     * Netmask bit counts are the same, so check all the address bits.
     */
    order = bitncmp(gk_ip_addr(key), ip_addr(query), gk_ip_maxbits(key));

    switch (strategy)
    {
        case INETSTRAT_LT:
            PG_RETURN_BOOL(order < 0);

        case INETSTRAT_LE:
            PG_RETURN_BOOL(order <= 0);

        case INETSTRAT_EQ:
            PG_RETURN_BOOL(order == 0);

        case INETSTRAT_GE:
            PG_RETURN_BOOL(order >= 0);

        case INETSTRAT_GT:
            PG_RETURN_BOOL(order > 0);

        case INETSTRAT_NE:
            PG_RETURN_BOOL(order != 0);
    }

    elog(ERROR, "unknown strategy for inet GiST");
    PG_RETURN_BOOL(false);        /* keep compiler quiet */
}

/*
 * Calculate parameters of the union of some GistInetKeys.
 *
 * Examine the keys in elements m..n inclusive of the GISTENTRY array,
 * and compute these output parameters:
 * *minfamily_p = minimum IP address family number
 * *maxfamily_p = maximum IP address family number
 * *minbits_p = minimum netmask width
 * *commonbits_p = number of leading bits in common among the addresses
 *
 * minbits and commonbits are forced to zero if there's more than one
 * address family.
 */
static void
calc_inet_union_params(GISTENTRY *ent,
                       int m, int n,
                       int *minfamily_p,
                       int *maxfamily_p,
                       int *minbits_p,
                       int *commonbits_p)
{// #lizard forgives
    int            minfamily,
                maxfamily,
                minbits,
                commonbits;
    unsigned char *addr;
    GistInetKey *tmp;
    int            i;

    /* Must be at least one key. */
    Assert(m <= n);

    /* Initialize variables using the first key. */
    tmp = DatumGetInetKeyP(ent[m].key);
    minfamily = maxfamily = gk_ip_family(tmp);
    minbits = gk_ip_minbits(tmp);
    commonbits = gk_ip_commonbits(tmp);
    addr = gk_ip_addr(tmp);

    /* Scan remaining keys. */
    for (i = m + 1; i <= n; i++)
    {
        tmp = DatumGetInetKeyP(ent[i].key);

        /* Determine range of family numbers */
        if (minfamily > gk_ip_family(tmp))
            minfamily = gk_ip_family(tmp);
        if (maxfamily < gk_ip_family(tmp))
            maxfamily = gk_ip_family(tmp);

        /* Find minimum minbits */
        if (minbits > gk_ip_minbits(tmp))
            minbits = gk_ip_minbits(tmp);

        /* Find minimum number of bits in common */
        if (commonbits > gk_ip_commonbits(tmp))
            commonbits = gk_ip_commonbits(tmp);
        if (commonbits > 0)
            commonbits = bitncommon(addr, gk_ip_addr(tmp), commonbits);
    }

    /* Force minbits/commonbits to zero if more than one family. */
    if (minfamily != maxfamily)
        minbits = commonbits = 0;

    *minfamily_p = minfamily;
    *maxfamily_p = maxfamily;
    *minbits_p = minbits;
    *commonbits_p = commonbits;
}

/*
 * Same as above, but the GISTENTRY elements to examine are those with
 * indices listed in the offsets[] array.
 */
static void
calc_inet_union_params_indexed(GISTENTRY *ent,
                               OffsetNumber *offsets, int noffsets,
                               int *minfamily_p,
                               int *maxfamily_p,
                               int *minbits_p,
                               int *commonbits_p)
{// #lizard forgives
    int            minfamily,
                maxfamily,
                minbits,
                commonbits;
    unsigned char *addr;
    GistInetKey *tmp;
    int            i;

    /* Must be at least one key. */
    Assert(noffsets > 0);

    /* Initialize variables using the first key. */
    tmp = DatumGetInetKeyP(ent[offsets[0]].key);
    minfamily = maxfamily = gk_ip_family(tmp);
    minbits = gk_ip_minbits(tmp);
    commonbits = gk_ip_commonbits(tmp);
    addr = gk_ip_addr(tmp);

    /* Scan remaining keys. */
    for (i = 1; i < noffsets; i++)
    {
        tmp = DatumGetInetKeyP(ent[offsets[i]].key);

        /* Determine range of family numbers */
        if (minfamily > gk_ip_family(tmp))
            minfamily = gk_ip_family(tmp);
        if (maxfamily < gk_ip_family(tmp))
            maxfamily = gk_ip_family(tmp);

        /* Find minimum minbits */
        if (minbits > gk_ip_minbits(tmp))
            minbits = gk_ip_minbits(tmp);

        /* Find minimum number of bits in common */
        if (commonbits > gk_ip_commonbits(tmp))
            commonbits = gk_ip_commonbits(tmp);
        if (commonbits > 0)
            commonbits = bitncommon(addr, gk_ip_addr(tmp), commonbits);
    }

    /* Force minbits/commonbits to zero if more than one family. */
    if (minfamily != maxfamily)
        minbits = commonbits = 0;

    *minfamily_p = minfamily;
    *maxfamily_p = maxfamily;
    *minbits_p = minbits;
    *commonbits_p = commonbits;
}

/*
 * Construct a GistInetKey representing a union value.
 *
 * Inputs are the family/minbits/commonbits values to use, plus a pointer to
 * the address field of one of the union inputs.  (Since we're going to copy
 * just the bits-in-common, it doesn't matter which one.)
 */
static GistInetKey *
build_inet_union_key(int family, int minbits, int commonbits,
                     unsigned char *addr)
{
    GistInetKey *result;
    Assert(commonbits >= 0);
    /* Make sure any unused bits are zeroed. */
    result = (GistInetKey *) palloc0(sizeof(GistInetKey));

    gk_ip_family(result) = family;
    gk_ip_minbits(result) = minbits;
    gk_ip_commonbits(result) = commonbits;

    /* Clone appropriate bytes of the address. */
    if (commonbits > 0)
        memcpy(gk_ip_addr(result), addr, (commonbits + 7) / 8);

    /* Clean any unwanted bits in the last partial byte. */
    if (commonbits % 8 != 0)
        gk_ip_addr(result)[commonbits / 8] &= ~(0xFF >> (commonbits % 8));

    /* Set varlena header correctly. */
    SET_GK_VARSIZE(result);

    return result;
}


/*
 * The GiST union function
 *
 * See comments at head of file for the definition of the union.
 */
Datum
inet_gist_union(PG_FUNCTION_ARGS)
{
    GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
    GISTENTRY  *ent = entryvec->vector;
    int            minfamily,
                maxfamily,
                minbits,
                commonbits;
    unsigned char *addr;
    GistInetKey *tmp,
               *result;

    /* Determine parameters of the union. */
    calc_inet_union_params(ent, 0, entryvec->n - 1,
                           &minfamily, &maxfamily,
                           &minbits, &commonbits);

    /* If more than one family, emit family number zero. */
    if (minfamily != maxfamily)
        minfamily = 0;

    /* Initialize address using the first key. */
    tmp = DatumGetInetKeyP(ent[0].key);
    addr = gk_ip_addr(tmp);

    /* Construct the union value. */
    result = build_inet_union_key(minfamily, minbits, commonbits, addr);

    PG_RETURN_POINTER(result);
}

/*
 * The GiST compress function
 *
 * Convert an inet value to GistInetKey.
 */
Datum
inet_gist_compress(PG_FUNCTION_ARGS)
{
    GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
    GISTENTRY  *retval;

    if (entry->leafkey)
    {
        retval = palloc(sizeof(GISTENTRY));
        if (DatumGetPointer(entry->key) != NULL)
        {
            inet       *in = DatumGetInetPP(entry->key);
            GistInetKey *r;

            r = (GistInetKey *) palloc0(sizeof(GistInetKey));

            gk_ip_family(r) = ip_family(in);
            gk_ip_minbits(r) = ip_bits(in);
            gk_ip_commonbits(r) = gk_ip_maxbits(r);
            memcpy(gk_ip_addr(r), ip_addr(in), gk_ip_addrsize(r));
            SET_GK_VARSIZE(r);

            gistentryinit(*retval, PointerGetDatum(r),
                          entry->rel, entry->page,
                          entry->offset, FALSE);
        }
        else
        {
            gistentryinit(*retval, (Datum) 0,
                          entry->rel, entry->page,
                          entry->offset, FALSE);
        }
    }
    else
        retval = entry;
    PG_RETURN_POINTER(retval);
}

/*
 * The GiST decompress function
 *
 * do not do anything --- we just use the stored GistInetKey as-is.
 */
Datum
inet_gist_decompress(PG_FUNCTION_ARGS)
{
    GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);

    PG_RETURN_POINTER(entry);
}

/*
 * The GiST fetch function
 *
 * Reconstruct the original inet datum from a GistInetKey.
 */
Datum
inet_gist_fetch(PG_FUNCTION_ARGS)
{
    GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
    GistInetKey *key = DatumGetInetKeyP(entry->key);
    GISTENTRY  *retval;
    inet       *dst;

    dst = (inet *) palloc0(sizeof(inet));

    ip_family(dst) = gk_ip_family(key);
    ip_bits(dst) = gk_ip_minbits(key);
    memcpy(ip_addr(dst), gk_ip_addr(key), ip_addrsize(dst));
    SET_INET_VARSIZE(dst);

    retval = palloc(sizeof(GISTENTRY));
    gistentryinit(*retval, InetPGetDatum(dst), entry->rel, entry->page,
                  entry->offset, FALSE);

    PG_RETURN_POINTER(retval);
}

/*
 * The GiST page split penalty function
 *
 * Charge a large penalty if address family doesn't match, or a somewhat
 * smaller one if the new value would degrade the union's minbits
 * (minimum netmask width).  Otherwise, penalty is inverse of the
 * new number of common address bits.
 */
Datum
inet_gist_penalty(PG_FUNCTION_ARGS)
{
    GISTENTRY  *origent = (GISTENTRY *) PG_GETARG_POINTER(0);
    GISTENTRY  *newent = (GISTENTRY *) PG_GETARG_POINTER(1);
    float       *penalty = (float *) PG_GETARG_POINTER(2);
    GistInetKey *orig = DatumGetInetKeyP(origent->key),
               *new = DatumGetInetKeyP(newent->key);
    int            commonbits;

    if (gk_ip_family(orig) == gk_ip_family(new))
    {
        if (gk_ip_minbits(orig) <= gk_ip_minbits(new))
        {
            commonbits = bitncommon(gk_ip_addr(orig), gk_ip_addr(new),
                                    Min(gk_ip_commonbits(orig),
                                        gk_ip_commonbits(new)));
            if (commonbits > 0)
                *penalty = 1.0f / commonbits;
            else
                *penalty = 2;
        }
        else
            *penalty = 3;
    }
    else
        *penalty = 4;

    PG_RETURN_POINTER(penalty);
}

/*
 * The GiST PickSplit method
 *
 * There are two ways to split. First one is to split by address families,
 * if there are multiple families appearing in the input.
 *
 * The second and more common way is to split by addresses. To achieve this,
 * determine the number of leading bits shared by all the keys, then split on
 * the next bit.  (We don't currently consider the netmask widths while doing
 * this; should we?)  If we fail to get a nontrivial split that way, split
 * 50-50.
 */
Datum
inet_gist_picksplit(PG_FUNCTION_ARGS)
{// #lizard forgives
    GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
    GIST_SPLITVEC *splitvec = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
    GISTENTRY  *ent = entryvec->vector;
    int            minfamily,
                maxfamily,
                minbits,
                commonbits;
    unsigned char *addr;
    GistInetKey *tmp,
               *left_union,
               *right_union;
    int            maxoff,
                nbytes;
    OffsetNumber i,
               *left,
               *right;

    maxoff = entryvec->n - 1;
    nbytes = (maxoff + 1) * sizeof(OffsetNumber);

    left = (OffsetNumber *) palloc(nbytes);
    right = (OffsetNumber *) palloc(nbytes);

    splitvec->spl_left = left;
    splitvec->spl_right = right;

    splitvec->spl_nleft = 0;
    splitvec->spl_nright = 0;

    /* Determine parameters of the union of all the inputs. */
    calc_inet_union_params(ent, FirstOffsetNumber, maxoff,
                           &minfamily, &maxfamily,
                           &minbits, &commonbits);

    if (minfamily != maxfamily)
    {
        /* Multiple families, so split by family. */
        for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
        {
            /*
             * If there's more than 2 families, all but maxfamily go into the
             * left union.  This could only happen if the inputs include some
             * IPv4, some IPv6, and some already-multiple-family unions.
             */
            tmp = DatumGetInetKeyP(ent[i].key);
            if (gk_ip_family(tmp) != maxfamily)
                left[splitvec->spl_nleft++] = i;
            else
                right[splitvec->spl_nright++] = i;
        }
    }
    else
    {
        /*
         * Split on the next bit after the common bits.  If that yields a
         * trivial split, try the next bit position to the right.  Repeat till
         * success; or if we run out of bits, do an arbitrary 50-50 split.
         */
        int            maxbits = ip_family_maxbits(minfamily);

        while (commonbits < maxbits)
        {
            /* Split using the commonbits'th bit position. */
            int            bitbyte = commonbits / 8;
            int            bitmask = 0x80 >> (commonbits % 8);

            splitvec->spl_nleft = splitvec->spl_nright = 0;

            for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
            {
                tmp = DatumGetInetKeyP(ent[i].key);
                addr = gk_ip_addr(tmp);
                if ((addr[bitbyte] & bitmask) == 0)
                    left[splitvec->spl_nleft++] = i;
                else
                    right[splitvec->spl_nright++] = i;
            }

            if (splitvec->spl_nleft > 0 && splitvec->spl_nright > 0)
                break;            /* success */
            commonbits++;
        }

        if (commonbits >= maxbits)
        {
            /* Failed ... do a 50-50 split. */
            splitvec->spl_nleft = splitvec->spl_nright = 0;

            for (i = FirstOffsetNumber; i <= maxoff / 2; i = OffsetNumberNext(i))
            {
                left[splitvec->spl_nleft++] = i;
            }
            for (; i <= maxoff; i = OffsetNumberNext(i))
            {
                right[splitvec->spl_nright++] = i;
            }
        }
    }

    /*
     * Compute the union value for each side from scratch.  In most cases we
     * could approximate the union values with what we already know, but this
     * ensures that each side has minbits and commonbits set as high as
     * possible.
     */
    calc_inet_union_params_indexed(ent, left, splitvec->spl_nleft,
                                   &minfamily, &maxfamily,
                                   &minbits, &commonbits);
    if (minfamily != maxfamily)
        minfamily = 0;
    tmp = DatumGetInetKeyP(ent[left[0]].key);
    addr = gk_ip_addr(tmp);
    left_union = build_inet_union_key(minfamily, minbits, commonbits, addr);
    splitvec->spl_ldatum = PointerGetDatum(left_union);

    calc_inet_union_params_indexed(ent, right, splitvec->spl_nright,
                                   &minfamily, &maxfamily,
                                   &minbits, &commonbits);
    if (minfamily != maxfamily)
        minfamily = 0;
    tmp = DatumGetInetKeyP(ent[right[0]].key);
    addr = gk_ip_addr(tmp);
    right_union = build_inet_union_key(minfamily, minbits, commonbits, addr);
    splitvec->spl_rdatum = PointerGetDatum(right_union);

    PG_RETURN_POINTER(splitvec);
}

/*
 * The GiST equality function
 */
Datum
inet_gist_same(PG_FUNCTION_ARGS)
{
    GistInetKey *left = DatumGetInetKeyP(PG_GETARG_DATUM(0));
    GistInetKey *right = DatumGetInetKeyP(PG_GETARG_DATUM(1));
    bool       *result = (bool *) PG_GETARG_POINTER(2);

    *result = (gk_ip_family(left) == gk_ip_family(right) &&
               gk_ip_minbits(left) == gk_ip_minbits(right) &&
               gk_ip_commonbits(left) == gk_ip_commonbits(right) &&
               memcmp(gk_ip_addr(left), gk_ip_addr(right),
                      gk_ip_addrsize(left)) == 0);

    PG_RETURN_POINTER(result);
}
